import socket
import time
import speech_recognition as sr
import whisper
import numpy as np
import scipy.signal

# 创建 socket 对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 定义服务器的 IP 地址和端口号
host = '192.168.35.117'  # 服务端的 IP 地址
port = 8080             # 服务端的端口

# 连接到服务器
def connect_to_server():
    try:
        client_socket.connect((host, port))
        print(f"[{time.strftime('%H:%M:%S')}] 已连接到服务器")
        return True
    except Exception as e:
        print(f"[{time.strftime('%H:%M:%S')}] 连接失败: {e}")
        return False

# 尝试初始连接
if not connect_to_server():
    exit(1)

# 语音命令映射到控制消息
VOICE_COMMANDS = {
    "前进": "linear x: 0.5, angular z: 0.0\n",
    "后退": "linear x: -0.5, angular z: 0.0\n",
    "停止": "linear x: 0.0, angular z: 0.0\n",
    "站起来": "linear x: 0.0, angular z: 0.0, action: 1\n",
    "坐下": "linear x: 0.0, angular z: 0.0, action: 0\n",
    "退出": "quit"
}
WAKE_WORD = "你好"
COMMAND_TIMEOUT = 100  # 命令模式超时时间（秒）

# 发送消息到服务器
def send_message(message):
    global client_socket
    try:
        client_socket.sendall(message.encode('utf-8'))
        print(f"[{time.strftime('%H:%M:%S')}] 已发送消息: {message.strip()}")
    except BrokenPipeError:
        print(f"[{time.strftime('%H:%M:%S')}] 连接已断开，尝试重新连接...")
        client_socket.close()
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        if connect_to_server():
            print(f"[{time.strftime('%H:%M:%S')}] 已重新连接到服务器")
            client_socket.sendall(message.encode('utf-8'))
            print(f"[{time.strftime('%H:%M:%S')}] 已发送消息: {message.strip()}")
        else:
            print(f"[{time.strftime('%H:%M:%S')}] 重新连接失败，稍后重试...")
            time.sleep(1)

# 处理语音命令
def process_command(command):
    if command == "quit":
        print(f"[{time.strftime('%H:%M:%S')}] 退出程序")
        global running
        running = False
        return
    send_message(command)

# 语音识别主循环
def speech_control():
    global running
    running = True
    recognizer = sr.Recognizer()
    recognizer.energy_threshold = 10000  # 适应更多语音输入
    recognizer.dynamic_energy_threshold = True  # 动态调整阈值

    # 加载 Whisper 模型
    try:
        print(f"[{time.strftime('%H:%M:%S')}] 加载 Whisper 模型...")
        whisper_model = whisper.load_model("small")
        print(f"[{time.strftime('%H:%M:%S')}] Whisper 模型加载成功")
    except Exception as e:
        print(f"[{time.strftime('%H:%M:%S')}] 加载 Whisper 模型失败: {e}")
        return

    def recognize_once(source):
        try:
            print(f"[{time.strftime('%H:%M:%S')}] 正在监听...")
            audio = recognizer.listen(source, timeout=5, phrase_time_limit=7)
            print(f"[{time.strftime('%H:%M:%S')}] 音频捕获成功，正在识别...")

            # 转换音频为 Whisper 格式
            audio_data = np.frombuffer(audio.get_wav_data(), dtype=np.int16).astype(np.float32) / 32768.0
            sample_rate = audio.sample_rate
            if sample_rate != 16000:
                num_samples = int(len(audio_data) * 16000 / sample_rate)
                audio_data = scipy.signal.resample(audio_data, num_samples)
                sample_rate = 16000

            # 使用 Whisper 识别
            result = whisper_model.transcribe(audio_data, language="zh", fp16=False)
            text = result["text"].strip()
            if text:
                print(f"[{time.strftime('%H:%M:%S')}] 识别到语音: {text}")
                return text
            else:
                print(f"[{time.strftime('%H:%M:%S')}] 未识别到有效文本")
                return None
        except sr.WaitTimeoutError:
            print(f"[{time.strftime('%H:%M:%S')}] 未检测到语音")
            return None
        except Exception as e:
            print(f"[{time.strftime('%H:%M:%S')}] 语音识别错误: {e}")
            return None

    try:
        with sr.Microphone() as source:
            print(f"[{time.strftime('%H:%M:%S')}] 可用麦克风设备: {sr.Microphone.list_microphone_names()}")
            print(f"[{time.strftime('%H:%M:%S')}] 正在调整环境噪音，请稍等...")
            recognizer.adjust_for_ambient_noise(source, duration=2)
            print(f"[{time.strftime('%H:%M:%S')}] 语音控制已启动，等待唤醒词：'你好'")
            print(f"[{time.strftime('%H:%M:%S')}] 支持的命令：前进、后退、停止、站起来、坐下、退出")

            is_awake = False
            last_command_time = time.time()

            while running:
                text = recognize_once(source)

                if not text:
                    # 超时或无效语音，检查命令模式超时
                    if is_awake and time.time() - last_command_time > COMMAND_TIMEOUT:
                        print(f"[{time.strftime('%H:%M:%S')}] 命令模式超时，回到等待唤醒词状态")
                        is_awake = False
                    continue

                # 等待唤醒词
                if not is_awake:
                    if WAKE_WORD in text:
                        print(f"[{time.strftime('%H:%M:%S')}] 唤醒成功！进入命令模式，请说出命令...")
                        is_awake = True
                        last_command_time = time.time()
                    continue

                # 命令模式
                for command, message in VOICE_COMMANDS.items():
                    if command in text:
                        print(f"[{time.strftime('%H:%M:%S')}] 处理命令: {command}")
                        process_command(message)
                        last_command_time = time.time()
                        break
                else:
                    print(f"[{time.strftime('%H:%M:%S')}] 未识别到有效命令: {text}")

                # 检查命令模式超时
                if is_awake and time.time() - last_command_time > COMMAND_TIMEOUT:
                    print(f"[{time.strftime('%H:%M:%S')}] 命令模式超时，回到等待唤醒词状态")
                    is_awake = False

                time.sleep(0.1)  # 降低 CPU 使用率
    except Exception as e:
        print(f"[{time.strftime('%H:%M:%S')}] 语音控制错误: {e}")
    finally:
        client_socket.close()
        print(f"[{time.strftime('%H:%M:%S')}] 连接已关闭")

# 主程序
if __name__ == "__main__":
    try:
        speech_control()
    except KeyboardInterrupt:
        print(f"[{time.strftime('%H:%M:%S')}] 客户端正在关闭...")
    finally:
        client_socket.close()
        print(f"[{time.strftime('%H:%M:%S')}] 连接已关闭")